/*****************************************************************************
*    Copyright (C)2003 Ali Corporation. All Rights Reserved.
*
*    File:    nim_sl1935.c
*
*    Description:    This file contains sl1935 basic function in LLD.
*    History:
*           Date            Athor        Version          Reason
*	    ============	=============	=========	=================
*	1.	june.2.2005     Hao Huang       Ver 0.1    Create file.
*
*****************************************************************************/

#include <sys_config.h>


#include <retcode.h>
#include <types.h>

#include <api/libc/printf.h>
#include <api/libc/string.h>
#include <bus/i2c/i2c.h>
#include <osal/osal_task.h>
#include "nim_st6000.h"


struct QPSK_TUNER_CONFIG_EXT * stSTB600_dev_id[MAX_TUNER_SUPPORT_NUM] = {NULL};
static UINT32 stSTB600_tuner_cnt = 0;
/*****************************************************************************
* INT32 nim_ST6000_init(UINT32 para, struct QPSK_TUNER_CONFIG_EXT * ptrTuner_Config)
*
* Tuner STB6000 Initialization
*
* Arguments:
*  Parameter1: UINT32 para		: Input Parameter
*  Parameter2: struct QPSK_TUNER_CONFIG_EXT * ptrTuner_Config		: pointer for Tuner configuration structure
*
* Return Value: INT32			: Result
*****************************************************************************/
INT32 nim_st6000_init(UINT32* tuner_id, struct QPSK_TUNER_CONFIG_EXT * ptrTuner_Config)
{
	struct QPSK_TUNER_CONFIG_EXT * stSTB600_ptr = NULL;
	/* check Tuner Configuration structure is available or not */
	if (ptrTuner_Config == NULL||stSTB600_tuner_cnt>=MAX_TUNER_SUPPORT_NUM)
		return ERR_FAILUE;
	stSTB600_ptr = (struct QPSK_TUNER_CONFIG_EXT *)MALLOC(sizeof(struct QPSK_TUNER_CONFIG_EXT));
	if(!stSTB600_ptr)
		return ERR_FAILUE;
	stSTB600_dev_id[stSTB600_tuner_cnt] = stSTB600_ptr;
	MEMCPY(stSTB600_ptr, ptrTuner_Config, sizeof(struct QPSK_TUNER_CONFIG_EXT));
	*tuner_id = stSTB600_tuner_cnt;
	stSTB600_tuner_cnt++;
/*	soc_printf("%s: sizeof QPSK_TUNER_CONFIG_EXT = %d\n", __FUNCTION__, sizeof(struct QPSK_TUNER_CONFIG_EXT));
	soc_printf("Base Address: 0x%x\n",stSTB600_Config.cTuner_Base_Addr);
	soc_printf("Tuner Crystal: %dKHz\n",stSTB600_Config.wTuner_Crystal);
	soc_printf("Output Mode: %d (1 -- Signle End; 0 -- Differential)\n",stSTB600_Config.cTuner_Out_S_D_Sel);
*/
	return SUCCESS;
}

/*****************************************************************************
* INT32 nim_ST6000_write(UINT8 reg,UINT8* buff,UINT8 len)
*
* Tuner write register from ST6000
*
* Arguments:
*  Parameter1: UINT8 reg		: Register offset of ST6000
*  Parameter2: UINT8* buff		: write data buffer
*  Parameter3: UINT8 len		: write length
*
* Return Value: INT32			: Result
*****************************************************************************/
INT32 nim_ST6000_write(UINT32 i2c_type_id, UINT8 base_addr, UINT8 reg,UINT8* buff,UINT8 len)
{
	UINT8  i, buffer[13];
	INT32  result = 0x200;

	if (len > 12)
	{
	    return ERR_FAILUE;
	}
	buffer[0] = reg;
	for (i = 0; i < len; i++)
	{
	    buffer[i + 1] = buff[i];
		MST6000_DEBUG("data[%d] is 0x%x\n", i+1, buffer[i + 1] );
	}

	return i2c_write(i2c_type_id, base_addr, buffer, len+1);
}

/*****************************************************************************
* INT32 nim_sl1935_control(UINT32 freq, UINT8 bs, UINT8 cp)
*
* Tuner write operation
*
* Arguments:
*  Parameter1: UINT32 freq		: Synthesiser programmable divider
*  Parameter2: UINT8 bs			: Baseband path select
*
* Return Value: INT32			: Result
*****************************************************************************/
INT32 nim_st6000_control(UINT32 tuner_id, UINT32 freq, UINT16 sym )
{
	UINT8 data[11];
	UINT8 ODIV, vco, N_counter, A_counter, R_divider;
	UINT8 K, G_gain, LPF, DLB, FCL, XOG;
	UINT32 Rs, BW;
	UINT16 temp;
	struct QPSK_TUNER_CONFIG_EXT * stSTB600_ptr = NULL;
	if(tuner_id>=stSTB600_tuner_cnt||tuner_id>=MAX_TUNER_SUPPORT_NUM)
		return ERR_FAILUE;
	stSTB600_ptr = stSTB600_dev_id[tuner_id];

	if( 1075 >= freq )
		ODIV = 1;
	else
		ODIV = 0;

	if( freq < 1000 )
		vco = 10;
	else if( freq < 1076 )
		vco = 12;
	else if( freq < 1200 )
		vco = 0;
	else if( freq < 1300 )
		vco = 1;
	else if( freq < 1370 )
		vco = 2;
	else if( freq < 1470 )
		vco = 4;
	else if( freq < 1530 )
		vco = 5;
	else if( freq < 1650 )
		vco = 6;
	else if( freq < 1800 )
		vco = 8;
	else if( freq < 1950 )
		vco = 10;
	else
		vco = 12;

    if(stSTB600_ptr->wTuner_Crystal == 13500)
        R_divider = 14;
    else
	    R_divider = 4;

	if( 0 == ODIV )
		temp = freq * R_divider * 1000 / stSTB600_ptr->wTuner_Crystal;
	else
		temp = freq * R_divider * 2 * 1000 / stSTB600_ptr->wTuner_Crystal;

	N_counter = temp/16;
	A_counter = temp%16;


	// LPF cut_off
	Rs = sym;
	if (Rs==0)
		Rs = 45000;
	//else			//HaoHuang add for debugging,
	//	Rs = 30000;

	BW = Rs*135/200;                // rolloff factor is 35%
	if (Rs<6500)  BW = BW + 3000;   // add 3M when Rs<5M, since we need shift 3M to avoid DC
	BW = BW + 2000;                 // add 2M for LNB frequency shifting
	BW = BW*130/100;                // 0.1dB to 3dB need about 30% transition band for 5th order LPF
	BW = BW*108/100;                // add 8% margin since fc is not very accurate
	if (BW< 5000)   BW =  5000;     // STB6000 LPF can be tuned form 5M to 36M, step is 1.0M
	if (BW>36000)   BW = 36000;
	LPF = BW/1000 - 5;


	K = 0x00;
	//G_gain = 0x07;	//DavidOU5712
	if (Rs>=17000) 	//20M - 0dB
		G_gain = 0x07;
	else if (Rs>=12000)
		G_gain = 0x08;
	else if (Rs>=6000) //10M - 4dB
		G_gain = 0x09;
	else if (Rs>=1500) // 2M - 6dB
		G_gain = 0x0a;
	else
		G_gain = 0x0b;
	DLB = 0x02;//0x03;	//DC Loop BW = 320Hz or 500Hz
	FCL = 0x00;//0x02;	//F_ref=1MHz or 4MHz

	if(stSTB600_ptr->wTuner_Crystal == 13500)
        	XOG = 0x01;
    	else
	    	XOG = 0x00;

	//data[9] = 0xEB;			//DavidOU add.
	//nim_ST6000_write(stSTB600_ptr->i2c_type_id, stSTB600_ptr->cTuner_Base_Addr, 0x0A, data+9, 1);

	data[0] = 0xC0 | (ODIV<<4) | vco;
	data[1] = N_counter>>1;
	data[2] = 0x60 | (N_counter<<7) | A_counter;
	data[3] = (K<<6) | R_divider;
	data[4] = 0x00 | G_gain;
	data[5] = 0x80 | LPF;
	data[6] = 0xC0 | (DLB<<3) | FCL;
	data[7] = 0xD0;
	data[8] = 0x50;
	data[9] = 0xEB;
	data[10] = 0x4F | (XOG<<7);
	nim_ST6000_write(stSTB600_ptr->i2c_type_id, stSTB600_ptr->cTuner_Base_Addr, 0x01, data, 11);

	data[9] = 0xFB;
	nim_ST6000_write(stSTB600_ptr->i2c_type_id, stSTB600_ptr->cTuner_Base_Addr, 0x0A, data+9, 1);

	osal_delay(30000);

	data[0] = 0x60 | (ODIV<<4) | vco;
	data[1] = N_counter>>1;
	data[2] = 0x60 | (N_counter<<7) | A_counter;
	data[3] = (K<<6) | R_divider;
	data[4] = 0x00 | G_gain;
	data[5] = 0x80 | LPF;
	data[6] = 0xC7 | (DLB<<3) ;
	nim_ST6000_write(stSTB600_ptr->i2c_type_id, stSTB600_ptr->cTuner_Base_Addr, 0x01, data, 7);

	//Power down mode
	//data[9] = 0x8B;
	//data[10] = 0x49;
	//nim_ST6000_write(stSTB600_ptr->i2c_type_id, stSTB600_ptr->cTuner_Base_Addr, 0x0A, data+9, 2);

	return SUCCESS;
}

/*****************************************************************************
* INT32 nim_sl1935_status(UINT8 *lock)
*
* Tuner read operation
*
* Arguments:
*  Parameter1: UINT8 *lock		: Phase lock status
*
* Return Value: INT32			: Result
*****************************************************************************/
INT32 nim_st6000_status(UINT32 tuner_id, UINT8 *lock)
{
	INT32 i,result;
	UINT8 data[12];
	struct QPSK_TUNER_CONFIG_EXT * stSTB600_ptr = NULL;
	if(tuner_id>=stSTB600_tuner_cnt||tuner_id>=MAX_TUNER_SUPPORT_NUM)
	{
		*lock = 0;
		return ERR_FAILUE;
	}
	stSTB600_ptr = stSTB600_dev_id[tuner_id];
	
	result = i2c_read(stSTB600_ptr->i2c_type_id, stSTB600_ptr->cTuner_Base_Addr+1, data, 1);
	for (i=0; i<1; i++)
		MST6000_DEBUG("I2C read data[%d] is 0x%x\n", i, data[i] );
	*lock = data[0]&0x01;
	MST6000_DEBUG("I2C read return is0x%x\n", result);
	return result;
}

